package models.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import framework.base.BaseModel;
import framework.utils.StringUtil;
import models.security.utils.SecurityConstant;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

@Entity
@Table(name="T_PERMISSION")
public class Permission extends BaseModel {
    //资源编码
    public String code;
    //资源类型 MENU:资源 ACTION:操作
    public String category;
    
    @ManyToMany(cascade=CascadeType.REFRESH,mappedBy="permissions") 
    public List<Role> roles = new ArrayList<Role>();

    
    public Permission(){
        
    }
    
    public Permission(String code,String category){
        this.code = code;
        this.category = category;
        this.status = USE_STATUS;
    }
    
    /**
     * 所有菜单的资源编码
     * @return
     */
    public static Set<String> allMenusCode(){
        Set<String> result = new HashSet<String>();
        List<Permission> permissions =  queryByType(SecurityConstant.RESOURCE_MENU_TYPE_NAME);
        for(Permission p : permissions){
            result.add(p.code);
        }
        return result;
    }
    
    /**
     * 所有操作的资源编码
     * @return
     */
    public static Set<String> allActionsCode(){
        Set<String> result = new HashSet<String>();
        List<Permission> permissions =  queryByType(SecurityConstant.RESOURCE_ACTION_TYPE_NAME);
        for(Permission p : permissions){
            result.add(p.code);
        }
        return result;
    }
    
    
    /**
     * 查询所有的权限信息
     * @param type
     * @return
     */
    public static List<Permission> queryByType(String category){
        String sql = "from Permission a where a.category=?";
        return Permission.find(sql, category).fetch();
    }
    
    /**
     * 增加权限信息
     * @param codes
     * @param type
     */
    public static void batchAdd(Set<String> codes ,String type){
        for(String code : codes){
            Permission p = new Permission(code,type);
            p.save();
        }
    }
    
    /**
     * 根据资源的编号长度获取资源集合
     * @param len
     * @return
     */
    public static List<Permission> queryByCodeLen(int len){
        String sql ="from Permission a where length(a.code)=? and a.category=? order by a.code asc";
        return Permission.find(sql, len,SecurityConstant.RESOURCE_MENU_TYPE_NAME).fetch();
    }
    
    /**
     * 获取所有的根节点菜单
     * @return
     */
    public static List<Permission> rootPermissions(){
        return queryByCodeLen(3);
    }
    
    /**
     * 查找所有直接子节点
     * @return
     */
    public  List<Permission> queryNodes(){
        String sql="from Permission a where a.code like ? and a.id!=? and a.category=? order by a.code asc";
        return Permission.find(sql, this.code+"%",this.id,SecurityConstant.RESOURCE_MENU_TYPE_NAME).fetch();
    }
    
    /**
     * 查询所有操作权限
     * @return
     */
    public List<Permission> queryActions(){
        String sql="from Permission a where a.code like ? and a.category=? order by a.code asc";
        return Permission.find(sql, this.code+"%",SecurityConstant.RESOURCE_ACTION_TYPE_NAME).fetch();
    }
    /**
     * 是否是根菜单
     * @return
     */
    public boolean isRootMenu(){
        boolean rcode = false;
        int len  = StringUtil.trim(this.code).length();
        if(SecurityConstant.RESOURCE_MENU_TYPE_NAME.equals(this.category) &&len==3){
            rcode  = true;
        }
        return rcode;
    }
    
    /**
     * 是否是菜单
     * @return
     */
    public boolean isMenu(){
        return SecurityConstant.RESOURCE_MENU_TYPE_NAME.equals(this.category);
    }
    
    /**
     * 父亲节点的编号
     * @return
     */
    public String rootCode(){
        String parentCode = this.code;
        if(!this.isRootMenu()){
            int len = this.code.length();
            parentCode = this.code.substring(0,len-3);
        }
        return parentCode;      
    }

    
    /**
     * 构造权限树
     */
    public static JSONArray toMenuJson(){
        List<Permission> roots = Permission.rootPermissions();
        Map<String,String> dics = Resource.resourcesDic();
        Set<String> codes = Resource.allResourceCodes();
        List<Permission> nodes = null;
        List<Permission> actions = null;
        JSONArray array = new JSONArray();
        JSONObject obj = new JSONObject();
        obj.put("id",0);
        obj.put("pId", -1);
        obj.put("name", "系统资源");
        obj.put("ptype", "rootPoint");
        obj.put("open", true);
        array.add(obj);
        for(Permission p : roots){
            obj = new JSONObject();
            obj.put("id",p.id);
            obj.put("pId", 0);
            obj.put("name", StringUtil.trim(dics.get(p.code)));
            obj.put("ptype", "root");
            obj.put("open", true);
            if(codes.contains(p.code)){
                array.add(obj);
            }
            nodes = p.queryNodes();
            for(Permission node : nodes){
                obj = new JSONObject();
                obj.put("id",node.id);
                obj.put("pId", p.id);
                obj.put("name", StringUtil.trim(dics.get(node.code)));
                obj.put("ptype", "node");
                obj.put("open", true);
                if(codes.contains(node.code)){
                    array.add(obj);
                }
                actions = node.queryActions();
                for(Permission action : actions){
                    obj = new JSONObject();
                    obj.put("id",action.id);
                    obj.put("pId", node.id);
                    obj.put("name", StringUtil.trim(dics.get(action.code)));
                    obj.put("ptype", "action");
                    if(codes.contains(action.code)){
                        array.add(obj);
                    }
                }
            }
        }
        return array;
    }
    
    
    public static Map<String,String> initResource( Collection<Permission> permissions){
        Map<String,String> result = new HashMap<String,String>();
        JSONObject menuObj = new JSONObject();
        JSONObject actionObj = new JSONObject();
        Set<String> codes = Resource.allResourceCodes();
        if(null!=permissions){
            String rootCode="";
            for(Permission  permission : permissions){
                rootCode = permission.rootCode();
                JSONArray array = null;
                if(SecurityConstant.RESOURCE_MENU_TYPE_NAME.equals(permission.category)){
                    if(!menuObj.containsKey(rootCode)){
                        array = new JSONArray();
                        if(codes.contains(rootCode)){
                            array.add(rootCode);
                            menuObj.put(rootCode, array);
                        }
                        if(!rootCode.equals(permission.code)){
                            menuObj.accumulate(rootCode,permission.code);
                        }
                        
                    }else{
                        if(!permission.code.equals(rootCode)){
                            menuObj.accumulate(rootCode,permission.code);
                        }
                    }
                }else{
                    if(!actionObj.containsKey(rootCode)){
                        array = new JSONArray();
                        if(codes.contains(permission.code)){
                            array.add(permission.code);
                            actionObj.put(rootCode, array);
                        }
                    }else{
                        if(codes.contains(permission.code)){
                            actionObj.accumulate(rootCode,permission.code);
                        }
                    }
                }
            }
        }
        result.put(SecurityConstant.RESOURCE_MENU_TYPE_NAME,menuObj.toString());
        result.put(SecurityConstant.RESOURCE_ACTION_TYPE_NAME, actionObj.toString());
        return result;
    }

    
}
